
package com.boby.homecamera.view;


import static java.lang.Math.max;
import static java.lang.Math.min;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Build;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Scroller;

import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.boby.homecamera.R;
import com.boby.lib_common.util.BLog;
import com.boby.lib_common.util.DateUtil;

import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;

import kotlin.jvm.Synchronized;

/**
 * TimeRuleView - 竖直方向显示的时间尺控件
 */
public class TimeRuleView extends View {
private static final String TAG = "TimeRuleView";
    private static final boolean LOG_ENABLE = true;
    public  int DAY_TIME_VALUE = 24 * 3600_000;

    private int bgColor;
    private int gradationColor;
    private float partHeight;
    private int partColor;
    private float gradationWidth;
    private float secondLen;
    private float minuteLen;
    private float hourLen;
    private int gradationTextColor;
    private float gradationTextSize;
    private float gradationTextGap;

    private long currentTime;
    private int indicatorColor;
    private float indicatorTriangleSideLen;
    private float indicatorWidth;

    // 单位秒数数组
    private static int[] mUnitSeconds = { //刻度间隔秒数
            10_000,     10_000,     10_000,     10_000,
            60_000,     60_000,
            5*60_000,   5*60_000,
            15 * 60_000, 15 * 60_000, 15 * 60_000, 15 * 60_000, 15 * 60_000, 15 * 60_000
    };

    private static int[] mPerTextCounts = {//文字间隔 秒
            60_000,         60_000,         2 * 60_000,     4 * 60_000,
            5 * 60_000,     10 * 60_000,
            20 * 60_000,    30 * 60_000,
            3600_000,       2 * 3600_000,   3 * 3600_000,   4 * 3600_000,   5 * 3600_000,   6 * 3600_000
    };

    private float[] mPerCountScaleThresholds = {
            6f,     3.6f,   1.8f,   1.5f,
            0.8f,     0.4f,
            0.25f,  0.125f,
            0.07f,  0.04f,  0.03f,  0.025f, 0.02f,  0.015f
    };

    private float mScale = 1;
    private final float mOneSecondGap = dp2px(12) / 60f;
    private float mUnitGap = mOneSecondGap * 60;//刻度间隔距离
    private int mPerTextCountIndex = 4;
    private int mUnitSecond = mUnitSeconds[mPerTextCountIndex];//刻度间隔秒

    private final float mTextHalfWidth;

    private final int SCROLL_SLOP;
    private final int MIN_VELOCITY;
    private final int MAX_VELOCITY;

    private float mCurrentDistance;

    private Paint mPaint;
    private TextPaint mTextPaint;
    private Path mTrianglePath;
    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;

    private ScaleGestureDetector mScaleGestureDetector;


    private int mWidth, mHeight;
    private int mHalfHeight;

    private int mInitialY;
    private int mLastX, mLastY;
    private boolean isMoving;
    private boolean isScaling;

    private List<TimePart> mTimePartList;
    private int lastDrawStartIndex = -1;
    private int lastDrawPart1StartIndex = -1;
    private int lastDrawPart2StartIndex = -1;
    private List<TimePart> mTimeEventPartList1;
    private List<TimePart> mTimeEventPartList2;
    private OnTimeChangedListener mListener;

    public interface OnTimeChangedListener {
        void onTimeChanged(long newTimeValue,boolean isEnd);
    }

    public static class TimePart {
        public long startTime;
        public long endTime;
        public int color;
    }

    public TimeRuleView(Context context) {
        this(context, null);
    }

    public TimeRuleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TimeRuleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);

        init(context);
        initScaleGestureDetector(context);

        mTextHalfWidth = mTextPaint.measureText("00:00") * .5f;
        ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
        SCROLL_SLOP = viewConfiguration.getScaledTouchSlop();
        MIN_VELOCITY = viewConfiguration.getScaledMinimumFlingVelocity();
        MAX_VELOCITY = viewConfiguration.getScaledMaximumFlingVelocity();

        calculateValues();
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TimeRuleView);
        bgColor = ta.getColor(R.styleable.TimeRuleView_zjun_bgColor, Color.parseColor("#EEEEEE"));
        gradationColor = ta.getColor(R.styleable.TimeRuleView_zjun_gradationColor, Color.GRAY);
        partHeight = ta.getDimension(R.styleable.TimeRuleView_trv_partHeight, dp2px(20));
        partColor = ta.getColor(R.styleable.TimeRuleView_trv_partColor, Color.parseColor("#F58D24"));
        gradationWidth = ta.getDimension(R.styleable.TimeRuleView_trv_gradationWidth, 1);
        secondLen = ta.getDimension(R.styleable.TimeRuleView_trv_secondLen, dp2px(3));
        minuteLen = ta.getDimension(R.styleable.TimeRuleView_trv_minuteLen, dp2px(5));
        hourLen = ta.getDimension(R.styleable.TimeRuleView_trv_hourLen, dp2px(10));
        gradationTextColor = ta.getColor(R.styleable.TimeRuleView_trv_gradationTextColor, Color.GRAY);
        gradationTextSize = ta.getDimension(R.styleable.TimeRuleView_trv_gradationTextSize, sp2px(12));
        gradationTextGap = ta.getDimension(R.styleable.TimeRuleView_trv_gradationTextGap, dp2px(2));
        currentTime = ta.getInt(R.styleable.TimeRuleView_trv_currentTime, 0);
        indicatorTriangleSideLen = ta.getDimension(R.styleable.TimeRuleView_trv_indicatorTriangleSideLen, dp2px(15));
        indicatorWidth = ta.getDimension(R.styleable.TimeRuleView_zjun_indicatorLineWidth, dp2px(1));
        indicatorColor = ta.getColor(R.styleable.TimeRuleView_zjun_indicatorLineColor, Color.RED);
        ta.recycle();
    }

    private void calculateValues() {
        mCurrentDistance = ((float)(currentTime - startTime + offsetTime)) / mUnitSecond * mUnitGap;
    }

    private void init(Context context) {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setTextSize(gradationTextSize);
        mTextPaint.setColor(gradationTextColor);

        mTrianglePath = new Path();
        mScroller = new Scroller(context);
    }

    private void initScaleGestureDetector(Context context) {
        float minSpan = ViewConfiguration.get(context).getScaledTouchSlop();
        mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.OnScaleGestureListener() {
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                handleScale( detector.getScaleFactor());
                return true;
            }

            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                isScaling = true;
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                isScaling = false;
            }
        });
    }
    private void handleScale(float scaleFactor) {
        final float maxScale = mPerCountScaleThresholds[0];
        final float minScale = mPerCountScaleThresholds[mPerCountScaleThresholds.length - 1];

        float oldUnitGap = mUnitGap;
        int oldUnitSecond = mUnitSecond;

        // 1. 计算当前中心位置所表示的时间秒数
        float centerSecond = mCurrentDistance / oldUnitGap * oldUnitSecond;

        // 2. 更新 scale
        mScale *= scaleFactor;
        mScale = max(minScale, min(maxScale, mScale));

        // 3. 找到新的单位间隔
        mPerTextCountIndex = findScaleIndex(mScale);
        mUnitSecond = mUnitSeconds[mPerTextCountIndex];
        mUnitGap = mScale * mOneSecondGap * mUnitSecond/1000;

        // 4. 保证中心时间不变，重新计算当前距离
        mCurrentDistance = (centerSecond / mUnitSecond) * mUnitGap;

//        BLog.d("handleScale", String.format("scale=%.2f, unitSecond=%d, unitGap=%.2f, curDist=%.2f", mScale, mUnitSecond, mUnitGap, mCurrentDistance));

        invalidate();
    }

    private float lastDistance = 0f;
    private boolean onScale(MotionEvent event){
        int pointerCount = event.getPointerCount();

        if (pointerCount == 2) {
            int action = event.getActionMasked();

            float x1 = event.getX(0);
            float y1 = event.getY(0);
            float x2 = event.getX(1);
            float y2 = event.getY(1);

            float dx = x2 - x1;
            float dy = y2 - y1;
            float distance = (float) Math.sqrt(dx * dx + dy * dy);

            switch (action) {
                case MotionEvent.ACTION_POINTER_DOWN:
                    lastDistance = distance;
                    isScaling = true;
                    break;

                case MotionEvent.ACTION_MOVE:
                    if (isScaling) {
                        float scaleFactor = distance / lastDistance;
                        if (Math.abs(scaleFactor - 1f) > 0.01f) {
                            handleScale(scaleFactor); // 你自己实现的方法
                            lastDistance = distance;
                        }
                    }
                    break;

                case MotionEvent.ACTION_POINTER_UP:
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    isScaling = false;
                    break;
            }
            return true; // 消费事件
        } else {
            isScaling = false;
        }
        return false;
    }
    private int findScaleIndex(float scale) {
        int size = mPerCountScaleThresholds.length;
        int min = 0, max = size - 1, mid = (min + max) >> 1;

        while (!(scale >= mPerCountScaleThresholds[mid] && scale < mPerCountScaleThresholds[mid - 1])) {
            if (scale >= mPerCountScaleThresholds[mid - 1]) {
                max = mid;
            } else {
                min = mid + 1;
            }
            mid = (min + max) >> 1;
            if (mid == 0 || min >= max) break;
        }
        return mid;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
        mHeight = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(mWidth, mHeight);
        mHalfHeight = mHeight >> 1;
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        if(event.getAction() == MotionEvent.ACTION_DOWN){
            getParent().requestDisallowInterceptTouchEvent(true);
        }
        return super.dispatchTouchEvent(event);
    }
    private boolean isTouchEnd = true;
    private boolean isScaled = false;
    private boolean isTouch = false;

    public boolean isTouch(){
        return  isTouch;
    }

    public long getLastTouchTime() {
        return lastTouchTime;
    }

    private long lastTouchTime = 0;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        lastTouchTime = System.currentTimeMillis();

        if(event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP){
            isTouch = false ;
        }else {
            isTouch = true ;
        }

        final int actionMasked = event.getActionMasked();
        final int y = (int) event.getY();
//        mScaleGestureDetector.onTouchEvent(event);
//        if (mScaleGestureDetector.isInProgress()) {
//            // 当前正在缩放，避免滑动冲突
//            return true;
//        }
        onScale(event);
//        BLog.d("onTouchEvent","Action:" + event.getAction() + " ,PointerCount:" + event.getPointerCount() );
        if(!isTouchEnd && isScaled){
            if(event.getPointerCount() <= 1  && (actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL)){
                isScaled = false;
                isTouchEnd = true;
            }
            return true;
        }
        if(event.getPointerCount() > 1){
            isScaled = true;
            isMoving = false;
            if (mVelocityTracker != null) {
                mVelocityTracker.recycle();
                mVelocityTracker = null;
            }
            return true ;
        }

//        BLog.d("onTouchEvent22","`````Action:" + event.getAction() + " ,PointerCount:" + event.getPointerCount() );
        if(event.getAction() == MotionEvent.ACTION_DOWN){
            isTouchEnd = false ;
        }

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);

        switch (actionMasked) {
            case MotionEvent.ACTION_DOWN:
                isMoving = false;
                mInitialY = y;
                if (!mScroller.isFinished()) {
                    mScroller.forceFinished(true);
                }
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                isScaling = true;
                isMoving = false;
                break;

            case MotionEvent.ACTION_MOVE:
                if (isScaling) break;
                int dy = y - mLastY;
                if (!isMoving) {
                    if (Math.abs(y - mInitialY) <= SCROLL_SLOP) break;
                    isMoving = true;
                }
                mCurrentDistance -= dy;
                computeTime(false);
                mLastY = y; // 👈 新增这一行
                break;

            case MotionEvent.ACTION_UP:
                isTouchEnd = true;
                if (isScaling || !isMoving) break;
                mVelocityTracker.computeCurrentVelocity(1000, MAX_VELOCITY);
                final int yVelocity = (int) mVelocityTracker.getYVelocity();
                if (Math.abs(yVelocity) >= MIN_VELOCITY) {
                    final int maxDistance = (int) (maxTimeValue / (mUnitSecond * 1.0) * mUnitGap);
                    mScroller.fling(0, (int) mCurrentDistance, 0, -yVelocity, 0, 0, 0, (int) maxDistance);

                    invalidate();
                }else {
                    computeTime(true);
                }
                if (mVelocityTracker != null) {
                    mVelocityTracker.recycle();
                    mVelocityTracker = null;
                }
                break;

            case MotionEvent.ACTION_POINTER_UP:
                isScaling = false;
                break;
            default:
                break;
        }
        mLastY = y;
        return true;
    }

    private void computeTime(boolean isTouchEnd) {
        float maxDistance = (float) maxTimeValue / mUnitSecond * mUnitGap;
        mCurrentDistance = min(maxDistance, max(0, mCurrentDistance));
        currentTime = startTime + (long) (((mCurrentDistance / mUnitGap) * (float) mUnitSecond) ) - offsetTime ;
        if (mListener != null) {
            mListener.onTimeChanged(currentTime,isTouchEnd);
        }
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
//        canvas.drawColor(bgColor);
        drawRule(canvas);
        drawTimeParts(canvas);
        drawTimeEventParts1(canvas);
        drawTimeIndicator(canvas);
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            final int maxDistance = (int) (maxTimeValue / (mUnitSecond * 1.0) * mUnitGap);
            mCurrentDistance = min(maxDistance, max(0, mScroller.getCurrY()));

            computeTime(mScroller.isFinished());
        }
    }
private long startTime = System.currentTimeMillis(); //一天的开始时间 毫秒

   private long maxTimeValue = DAY_TIME_VALUE; //最大时间 毫秒
   private long offsetTime = 0; //偏移时间 毫秒
    private long topDisplayTime = 0;
    private void drawRule(Canvas canvas) {
        mPaint.setColor(gradationColor);
        mPaint.setStrokeWidth(gradationWidth);

        long start = 0;

        float offset = mHalfHeight - mCurrentDistance;
        final int perTextCount = mPerTextCounts[mPerTextCountIndex];
        float maxLen = Float.max(Float.max(minuteLen, hourLen),minuteLen);
        float startX = mWidth/2f;
        long displayOffset = offsetTime%60_000;
//        BLog.d("drawRule"," displayOffset：" + displayOffset);
        long startOffset = displayOffset%mUnitSecond;
        start =  startOffset;
        offset += (float) startOffset/(float)mUnitSecond * mUnitGap;
        if(offset < -mUnitGap){
            int skipSize = (int)(-offset/mUnitGap);
            start += (long) mUnitSecond * skipSize ;
            offset += mUnitGap * skipSize;
        }
        topDisplayTime = startTime + start - displayOffset;
//        BLog.d("drawRule"," start：" + start + " ,offset：" + offset);
        while (start <= maxTimeValue) {
            if ((start - displayOffset) % 3600_000 == 0) {
                canvas.drawLine(startX , offset, startX + hourLen, offset, mPaint);
            } else if ((start - displayOffset) % 60_000 == 0) {
                canvas.drawLine(startX, offset, startX + minuteLen, offset, mPaint);
            } else {
                canvas.drawLine(startX, offset, startX + secondLen, offset, mPaint);
            }

            if ((start - displayOffset) % perTextCount == 0) {
                String text = DateUtil.formatTimeHHmm( startTime + start - displayOffset  );
//                canvas.drawText(text, startX + gradationTextGap + maxLen, offset + mTextPaint.getTextSize() / 2, mTextPaint);
                Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
                float baseline = offset - (fontMetrics.ascent + fontMetrics.descent) / 2;
                canvas.drawText(text, startX + gradationTextGap + maxLen, baseline, mTextPaint);
            }

            start += mUnitSecond;
            offset += mUnitGap;
            if(offset > mHeight){
                return;
            }
        }
    }

    private void drawTimeIndicator(Canvas canvas) {
        mPaint.setColor(indicatorColor);
        mPaint.setStrokeWidth(indicatorWidth);
        canvas.drawLine(0, mHalfHeight, mWidth, mHalfHeight, mPaint);

//        if (mTrianglePath.isEmpty()) {
//            float halfSideLen = indicatorTriangleSideLen * .5f;
//            mTrianglePath.moveTo(0, mHalfHeight - halfSideLen);
//            mTrianglePath.rLineTo(indicatorTriangleSideLen, indicatorTriangleSideLen);
//            mTrianglePath.rLineTo(-indicatorTriangleSideLen, 0);
//            mTrianglePath.close();
//        }
//        mPaint.setStyle(Paint.Style.FILL);
//        canvas.drawPath(mTrianglePath, mPaint);
        mPaint.setStyle(Paint.Style.STROKE);
    }

    private void drawTimeParts(Canvas canvas) {

        float startX = mWidth/2f - partHeight/2f;
//        float startX = 0;
        mPaint.setStrokeWidth(partHeight);

        float start, end;
        float secondGap = mUnitGap / mUnitSecond;
        //画背景
        mPaint.setColor(Color.GRAY);
        canvas.drawLine(startX, max(mHalfHeight - mCurrentDistance,0) , startX, min(mHalfHeight - mCurrentDistance + maxTimeValue * secondGap,mHeight), mPaint);

        if (mTimePartList == null) return;
        mPaint.setColor(partColor);
        int timeIndex = -1;
        if(lastDrawStartIndex == -1){
             timeIndex = findTimeIndex(mTimePartList, topDisplayTime);
        }else {
            timeIndex = findTimeIndex3(mTimePartList,lastDrawStartIndex, topDisplayTime);
        }

        lastDrawStartIndex = timeIndex;
        if(timeIndex < 0){
            timeIndex = 0;
        }
        for (int i = timeIndex; i < mTimePartList.size(); i++) {
            TimePart timePart = mTimePartList.get(i);
            start = mHalfHeight - mCurrentDistance + ((timePart.startTime - startTime) + offsetTime) * secondGap;
            end = mHalfHeight - mCurrentDistance + ((timePart.endTime - startTime)  + offsetTime) * secondGap;
            if(end > mHeight){
                canvas.drawLine(startX, max(0,start), startX, mHeight, mPaint);
//                BLog.d(TAG,"drawTimeParts: timeStartIndex:"+ timeIndex  +" endIndex:"+i);
                return;
            }
            if(end<=0){
                continue;
            }
            canvas.drawLine(startX, max(0,start), startX, end, mPaint);
        }

    }
    private int findTimeIndex(List<TimePart> timeList, long targetTime) {
        if (timeList == null || timeList.isEmpty()) {
            return -1;
        }

        // 1. 计算平均区间长度
        long firstStart = timeList.get(0).startTime;
        long lastEnd = timeList.get(timeList.size() - 1).endTime;
        long totalDuration = lastEnd - firstStart;
        long avgInterval = totalDuration / timeList.size();

        // 2. 预测目标时间可能的位置
        int predictedIndex = (int) ((targetTime - firstStart) / avgInterval);
        predictedIndex = Math.max(0, Math.min(predictedIndex, timeList.size() - 1));

        // 3. 检查预测位置附近的区间（线性探测）
        int searchRange = 3; // 检查预测位置附近的 3 个区间（可调整）
        int start = Math.max(0, predictedIndex - searchRange);
        int end = Math.min(timeList.size() - 1, predictedIndex + searchRange);

        for (int i = start; i <= end; i++) {
            TimePart current = timeList.get(i);
            if (targetTime >= current.startTime && targetTime <= current.endTime) {
                return i; // 找到匹配区间
            }
        }


        // 4. 如果预测失败，改用标准二分查找
        int left = 0;
        int right = timeList.size() - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            TimePart current = timeList.get(mid);

            if (targetTime >= current.startTime && targetTime <= current.endTime) {
                return mid;
            } else if (targetTime < current.startTime) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }

        return -1; // 未找到
    }
    private  final int SEARCH_RANGE = 16;
    private int findTimeIndex2(List<TimePart> timeList, int lastIndex,long targetTime) {
        if (timeList == null || timeList.isEmpty()) {
            return -1;
        }

        int maxListIndex = timeList.size() - 1;
        if(timeList.get(0).startTime <= targetTime){
            return 0;
        }else if(timeList.get(maxListIndex).endTime >= targetTime){
            return maxListIndex;
        }

        if(lastIndex < 0){
            lastIndex = 0;
        }else if(lastIndex >= timeList.size()){
            lastIndex = timeList.size() - 1;
        }

        //判断是 + searRange 还是 - searRange
        if(timeList.get(lastIndex).startTime >= targetTime && timeList.get(lastIndex).endTime < targetTime){
            return lastIndex ;
        }else if(timeList.get(lastIndex).startTime > targetTime){
            // - searRange
            int minIndex = max(lastIndex - SEARCH_RANGE,0);
            if(timeList.get(minIndex).startTime >= targetTime){
                lastIndex -- ;
                while (lastIndex >= minIndex){
                    if(timeList.get(lastIndex).startTime >= targetTime && timeList.get(lastIndex).endTime < targetTime){
                        return lastIndex;
                    }
                    lastIndex -- ;
                }
            }else {
                return findTimeIndex2(timeList,minIndex,targetTime);
            }

        }else  {
            // + searRange
            int maxIndex = max(lastIndex + SEARCH_RANGE,maxListIndex);
            if(timeList.get(maxIndex).endTime < targetTime){
                lastIndex ++ ;
                while (lastIndex <= maxIndex){
                    if(timeList.get(lastIndex).startTime >= targetTime && timeList.get(lastIndex).endTime < targetTime){
                        return lastIndex;
                    }
                    lastIndex ++ ;
                }
            }else {
                return findTimeIndex2(timeList,maxIndex,targetTime);
            }
            return maxListIndex;
        }


        return -1;
    }


    private int findTimeIndex3(List<TimePart> timeList, int lastIndex, long startTime) {
        if (timeList == null || timeList.isEmpty()) {
            return -1;
        }

        int maxListIndex = timeList.size() - 1;

        // 边界检查
        if(startTime <= timeList.get(0).startTime){
            return 0;
        }else if(startTime >= timeList.get(maxListIndex).endTime){
            return maxListIndex;
        }


        // 检查 lastIndex 是否合法
        if (lastIndex < 0) {
            lastIndex = 0;
        } else if (lastIndex > maxListIndex) {
            lastIndex = maxListIndex;
        }

        // 检查当前 lastIndex 是否匹配
        TimePart current = timeList.get(lastIndex);
        if (startTime >= current.startTime && startTime <= current.endTime) {
            return lastIndex;
        }

        // 判断搜索方向
        if (startTime < current.startTime) {
            // 向左搜索
            int minIndex = Math.max(lastIndex - SEARCH_RANGE, 0);
            for (int i = lastIndex - 1; i >= minIndex; i--) {
//                if (startTime >= timeList.get(i).startTime && startTime <= timeList.get(i).endTime) {
                if (startTime >= timeList.get(i).startTime ) {
//                    BLog.d(TAG,"findTimeIndex3: count:" + ( lastIndex - i));
                    return i;
                }
            }
//            BLog.d(TAG,"findTimeIndex3: lastIndex:" + lastIndex + ",minIndex:"+minIndex);
            // 如果没找到，递归向左缩小范围
            return findTimeIndex3(timeList, minIndex, startTime);

        } else {
            // 向右搜索
            int maxIndex = Math.min(lastIndex + SEARCH_RANGE, maxListIndex);
            for (int i = lastIndex + 1; i <= maxIndex; i++) {
//                if (startTime >= timeList.get(i).startTime && startTime <= timeList.get(i).endTime) {
                if ( startTime <= timeList.get(i).endTime) {
//                    BLog.d(TAG,"findTimeIndex3: count:" + ( i - lastIndex ));
                    return i;
                }
            }
            //findTimeIndex3: lastIndex startTime:1758978106046,endTime:1758978126166
            //findTimeIndex3: maxIndex startTime: 1758983665566,endTime:1758983766286
//            BLog.d(TAG,"findTimeIndex3: lastIndex startTime:" + timeList.get(lastIndex).startTime + ",endTime:"+timeList.get(lastIndex).endTime);
//            BLog.d(TAG,"findTimeIndex3: maxIndex startTime:" + timeList.get(maxIndex).startTime + ",endTime:"+timeList.get(maxIndex).endTime);
//            BLog.d(TAG,"findTimeIndex3: lastIndex:" +lastIndex + ",maxIndex:"+maxIndex);
            // 如果没找到，递归向右缩小范围
            return findTimeIndex3(timeList, maxIndex, startTime);
        }
    }
        @Synchronized
    private void drawTimeEventParts1(Canvas canvas) {
        boolean part1EventEmpty = mTimeEventPartList1 == null || mTimeEventPartList1.isEmpty();
        boolean part2EventEmpty = mTimeEventPartList2 == null || mTimeEventPartList2.isEmpty();

        if(part1EventEmpty && part2EventEmpty){
            return;
        }



        float start, end;
        float secondGap = mUnitGap / mUnitSecond;
        float startX = 0f;
        float partStartX = mWidth/2f - partHeight;
        mPaint.setStrokeWidth(partHeight/2f);
        if(!part1EventEmpty){
            if(part2EventEmpty){
                startX = partStartX + partHeight/2f;
            }else {
                startX = partStartX +  partHeight/4f;
            }
            int timeIndex = 0;
            if(lastDrawPart1StartIndex == -1){
                timeIndex = findTimeIndex(mTimeEventPartList1, topDisplayTime);
            }else {
                timeIndex = findTimeIndex3(mTimeEventPartList1,lastDrawPart1StartIndex, topDisplayTime);
            }

            lastDrawPart1StartIndex = timeIndex;
            if(timeIndex < 0){
                timeIndex = 0;
            }
            for (int i = timeIndex; i < mTimeEventPartList1.size(); i++) {
                TimePart timePart = mTimeEventPartList1.get(i);
                mPaint.setColor(timePart.color);
                start = mHalfHeight - mCurrentDistance + ((timePart.startTime - startTime) + offsetTime) * secondGap;
                end = mHalfHeight - mCurrentDistance + ((timePart.endTime - startTime)  + offsetTime) * secondGap;
                if(end > mHeight){
                    canvas.drawLine(startX, max(0,start), startX, mHeight, mPaint);
//                    BLog.d(TAG,"drawTimeEventParts1: timeStartIndex:"+ timeIndex  +" endIndex:"+i);
                    break;
                }
                if(end<=0){
                    continue;
                }
                canvas.drawLine(startX,  max(0,start), startX, end, mPaint);
            }

        }
        if(!part2EventEmpty){
            if(part1EventEmpty){
                startX = partStartX + partHeight/2f;
            }else {
                startX = partStartX + partHeight/4f * 3 ;
            }

            int timeIndex = 0;
            if(lastDrawPart2StartIndex == -1){
                timeIndex = findTimeIndex(mTimeEventPartList2, topDisplayTime);
            }else {
                timeIndex = findTimeIndex3(mTimeEventPartList2,lastDrawPart2StartIndex, topDisplayTime);
            }

            lastDrawPart2StartIndex = timeIndex;
            if(timeIndex < 0){
                timeIndex = 0;
            }
            for (int i = timeIndex; i < mTimeEventPartList2.size(); i++) {
                TimePart timePart = mTimeEventPartList2.get(i);
                mPaint.setColor(timePart.color);
                start = mHalfHeight - mCurrentDistance + ((timePart.startTime - startTime) + offsetTime) * secondGap;
                end = mHalfHeight - mCurrentDistance + ((timePart.endTime - startTime)  + offsetTime) * secondGap;

                if(end > mHeight){
                    canvas.drawLine(startX, max(0,start), startX, mHeight, mPaint);
//                    BLog.d(TAG,"drawTimeEventParts1 2: timeStartIndex:"+ timeIndex  +" endIndex:"+i);
                    break;
                }
                if(end<=0){
                    continue;
                }
                canvas.drawLine(startX,  max(0,start), startX, end, mPaint);
            }


        }
    }





    public static String formatTimeHHmmss( int timeValue) {
        int hour = timeValue / 3600;
        int minute = (timeValue % 3600) / 60;
        int second = timeValue % 60;
        return String.format("%02d:%02d:%02d", hour, minute, second);
    }

    private int dp2px(float dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }

    private int sp2px(float sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
    }

    private void logD(String format, Object... args) {
        if (LOG_ENABLE) {
            Log.d("TimeRuleView", "zjun@" + String.format(format, args));
        }
    }

    public void setOnTimeChangedListener(OnTimeChangedListener listener) {
        this.mListener = listener;
    }

    public void setStartTime(long startTime){
        this.startTime =startTime;//一天的开始时间
        calculateValues();
        invalidate();
    }
    public void setTimePartList(List<TimePart> timePartList) {
        this.mTimePartList = timePartList;

         offsetTime = 0 ;
         maxTimeValue = DAY_TIME_VALUE;
        if(mTimePartList != null && !mTimePartList.isEmpty() && mTimePartList.get(0).startTime < startTime){
            offsetTime = startTime - mTimePartList.get(0).startTime ;
            maxTimeValue += offsetTime;
        }

        if(mTimePartList != null && !mTimePartList.isEmpty() && (mTimePartList.get(mTimePartList.size() -1).endTime - startTime) > DAY_TIME_VALUE ){
            maxTimeValue +=  ((mTimePartList.get(mTimePartList.size() -1).endTime - startTime) - DAY_TIME_VALUE);
        }
        postInvalidate();
    }
    @Synchronized
    public void setTimeEventPartList(List<TimePart> timePartList1,List<TimePart> timePartList2) {
        this.mTimeEventPartList1 = timePartList1;
        this.mTimeEventPartList2 = timePartList2;
        postInvalidate();
    }

    public void setCurrentTime( long currentTime) {
        this.currentTime = currentTime;
        calculateValues();
        postInvalidate();

    }

}